package com.tian.service.impl;

import com.alibaba.fastjson.JSON;
import com.tian.common.CommonResult;
import com.tian.constant.RabbitMQConstant;
import com.tian.dto.UserBalanceChangeRespDto;
import com.tian.dto.UserBalanceDeductReqDto;
import com.tian.entity.UserBalance;
import com.tian.entity.UserBalanceChangeRecord;
import com.tian.enums.PayRetryMessageTypeEnum;
import com.tian.enums.PayStatusEnum;
import com.tian.enums.UserBalanceChangeTypeEnum;
import com.tian.mapper.UserBalanceChangeRecordMapper;
import com.tian.mapper.UserBalanceMapper;
import com.tian.message.ChargingOrderMessage;
import com.tian.message.MessageReqIdPrefixConstant;
import com.tian.message.UserPointMessage;
import com.tian.producer.MqProducer;
import com.tian.service.UserBalanceChangeService;
import com.tian.util.DateUtils;
import com.tian.util.UserCacheUtil;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

/**
 * {@code @description:} 用户余额变动服务实现类
 *
 * @author tianwc 公众号：Java后端技术全栈
 * 在线刷题 1200+java面试题和1000+篇技术文章：<a href="https://woaijava.cc/">博客地址</a>
 * {@code @date:} 2024-12-07 19:26
 * {@code @version:} 1.0
 */
@Slf4j
@Service
public class UserBalanceChangeServiceImpl implements UserBalanceChangeService {

    @Resource
    private UserBalanceChangeRecordMapper userBalanceChangeRecordMapper;
    @Resource
    private UserBalanceMapper userBalanceMapper;
    @Resource
    private RedissonClient redissonClient;
    @Resource
    private MqProducer mqProducer;

    @Override
    public CommonResult<List<UserBalanceChangeRespDto>> changeList() {
        Long userId = UserCacheUtil.getUser().getId();
        List<UserBalanceChangeRecord> userBalanceChangeRecords = userBalanceChangeRecordMapper.selectByUserId(userId);
        if (CollectionUtils.isEmpty(userBalanceChangeRecords)) {
            return CommonResult.success();
        }
        List<UserBalanceChangeRespDto> userBalanceChangeRespDtoList = new ArrayList<>();
        userBalanceChangeRecords.forEach(userBalanceChangeRecord -> {
            UserBalanceChangeRespDto userBalanceChangeRespDto = new UserBalanceChangeRespDto();
            userBalanceChangeRespDto.setType(UserBalanceChangeTypeEnum.getDesc(userBalanceChangeRecord.getChangeType()));
            BigDecimal changeBalance = userBalanceChangeRecord.getChangeBalance();
            changeBalance = changeBalance.setScale(2, RoundingMode.HALF_UP);
            String changeAmount = userBalanceChangeRecord.getChangeType() == UserBalanceChangeTypeEnum.USER_PAY.getType() ?
                    "-" + changeBalance : "+" + changeBalance;
            userBalanceChangeRespDto.setChangeAmount(changeAmount + " RMB");
            userBalanceChangeRespDto.setCreateTime(DateUtils.format(userBalanceChangeRecord.getCreateTime(), DateUtils.FORMAT_SECOND));
            userBalanceChangeRespDtoList.add(userBalanceChangeRespDto);
        });
        return CommonResult.success(userBalanceChangeRespDtoList);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public CommonResult<Boolean> deduct(UserBalanceDeductReqDto userBalanceDeductReqDto) {
        UserBalanceChangeRecord userBalanceChangeRecord = userBalanceChangeRecordMapper.selectByOrderNo(userBalanceDeductReqDto.getChargingRecordId().toString());
        if(userBalanceChangeRecord != null){
            log.info("订单已支付");
            return CommonResult.success(true);
        }
        Long userId = UserCacheUtil.getUser().getId();
        RLock lock = redissonClient.getLock("user_balance_lock_" + userId);
        try {
            lock.lock();
            UserBalance userBalance = userBalanceMapper.selectByUserId(userId);
            BigDecimal balance = userBalance.getBalance().subtract(userBalance.getFreezeBalance());
            if(balance.compareTo(userBalanceDeductReqDto.getDeductAmount()) < 0){
                return CommonResult.failed("余额不足");
            }
            BigDecimal afterBalance = balance.subtract(userBalanceDeductReqDto.getDeductAmount());
            userBalance.setBalance(afterBalance.add(userBalance.getFreezeBalance()));
            userBalanceMapper.updateByPrimaryKey(userBalance);

            // 发送market项目 新增用户积分消息

            UserBalanceChangeRecord userBalanceChangeRecordNew = new UserBalanceChangeRecord();
            userBalanceChangeRecordNew.setUserId(userId);
            userBalanceChangeRecordNew.setChangeType(UserBalanceChangeTypeEnum.USER_PAY.getType());
            userBalanceChangeRecordNew.setChangeBalance(userBalanceDeductReqDto.getDeductAmount());
            userBalanceChangeRecordNew.setBeforeBalance(balance);
            userBalanceChangeRecordNew.setAfterBalance(afterBalance);
            userBalanceChangeRecordNew.setOrderNo(userBalanceDeductReqDto.getChargingRecordId().toString());
            userBalanceChangeRecordNew.setCreateTime(new Date());
            userBalanceChangeRecordNew.setRemark("用户余额支付充电");
            userBalanceChangeRecordMapper.insert(userBalanceChangeRecordNew);

            sendChargingOrderStatus(userBalanceDeductReqDto.getChargingRecordId(), PayStatusEnum.PAID.getCode());
            sendUserPointAddMessage(userId, userBalanceDeductReqDto.getDeductAmount());
            return CommonResult.success(true);
        } finally {
            lock.unlock();
        }
    }

    /**
     * 给用户添加积分
     *
     * @param userId       用户id
     * @param changeAmount 消费金额
     */
    private void sendUserPointAddMessage(Long userId, BigDecimal changeAmount) {
        UserPointMessage userPointMessage = new UserPointMessage();
        userPointMessage.setUserId(userId);
        userPointMessage.setPoint(changeAmount.multiply(new BigDecimal(100)).intValue());
        userPointMessage.setReqId(MessageReqIdPrefixConstant.USER_POINT_ADD_REQ_ID_PREFIX
                + UUID.randomUUID() + DateUtils.formatDefaultDateMs());
        mqProducer.sendMessage(JSON.toJSONString(userPointMessage), RabbitMQConstant.USER_POINT_ADD_EXCHANGE, RabbitMQConstant.USER_POINT_ADD_ROUTING_KEY,
                PayRetryMessageTypeEnum.USER_POINT_ADD.getType());
    }

    /**
     * 充电订单状态变更
     *
     * @param chargeRecordId 充电记录id
     * @param status         充电记录状态
     */
    public void sendChargingOrderStatus(Long chargeRecordId, int status) {
        ChargingOrderMessage chargingOrderMessage = new ChargingOrderMessage();
        chargingOrderMessage.setOrderId(chargeRecordId);
        chargingOrderMessage.setStatus(status);
        mqProducer.sendMessage(JSON.toJSONString(chargingOrderMessage), RabbitMQConstant.CHARGING_ORDER_STATUS_CHANGE_EXCHANGE, RabbitMQConstant.CHARGING_ORDER_STATUS_CHANGE_ROUTING_KEY,
                PayRetryMessageTypeEnum.CHARGE_ORDER_STATUS_UPDATE.getType());
    }


}
